package com.beiyin.config;

import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.core.MessageProducer;
import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory;
import org.springframework.integration.mqtt.core.MqttPahoClientFactory;
import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter;
import org.springframework.integration.mqtt.outbound.MqttPahoMessageHandler;
import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.MessagingException;

import com.beiyin.service.MqttMessageHandler;

import org.springframework.messaging.Message;

@Configuration
public class MqttConfiguration {

    // 从应用配置文件中读取MQTT代理服务器的URL
    @Value("${mqtt.url}")
    private String url;

    // 从应用配置文件中读取MQTT客户端的唯一标识符
    @Value("${mqtt.clientId}")
    private String clientId;

    /**
     * 配置MQTT客户端工厂。
     * 这个工厂负责创建与MQTT代理服务器连接的客户端实例。
     * 这里配置了服务器的URL，但没有配置用户名和密码。
     * 如果MQTT代理需要认证，应该取消注释相关配置，并提供正确的用户名和密码。
     */
    @Bean
    public MqttPahoClientFactory mqttClientFactory() {
        DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();
        MqttConnectOptions options = new MqttConnectOptions();
        options.setServerURIs(new String[] { url });
        factory.setConnectionOptions(options);
        return factory;
    }

    /**
     * 定义一个消息通道，用于接收从MQTT代理接收到的消息。
     * DirectChannel是一种点对点的消息通道，意味着发送到该通道的每条消息都会直接传递给一个订阅者。
     */
    @Bean
    public MessageChannel mqttInputChannel() {
        return new DirectChannel();
    }

    /**
     * 配置MQTT Inbound适配器。
     * 这个适配器监听指定的MQTT主题（"topic1", "topic2"），并将接收到的消息发送到mqttInputChannel。
     * setCompletionTimeout设置了等待连接完成的超时时间。
     * setConverter设置了消息转换器，默认的转换器将MQTT消息转换为Spring Integration的Message对象。
     * setQos设置了消息的服务质量等级。
     */
    @Bean
    public MessageProducer inbound() {
        MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter(clientId + "_inbound",
                mqttClientFactory(),
                "topic1", "topic2");
        adapter.setCompletionTimeout(5000);
        adapter.setConverter(new DefaultPahoMessageConverter());
        adapter.setQos(1);
        adapter.setOutputChannel(mqttInputChannel());
        return adapter;
    }

    /**
     * 配置消息处理器，用于处理从mqttInputChannel接收到的消息。
     * 这个处理器是一个匿名内部类，它实现了MessageHandler接口。
     * handleMessage方法将接收到的消息的负载转换为字符串，并调用MqttMessageHandler的handleMessage方法进行处理。
     */
    @Bean
    @ServiceActivator(inputChannel = "mqttInputChannel")
    public MessageHandler handler(MqttMessageHandler mqttMessageHandler) {
        return new MessageHandler() {
            @Override
            public void handleMessage(Message<?> message) throws MessagingException {
                String payload = message.getPayload().toString();
                mqttMessageHandler.handleMessage(payload);
            }
        };
    }

    /**
     * 定义一个消息通道，用于发送消息到MQTT代理。
     * 与mqttInputChannel类似，这也是一个DirectChannel。
     */
    @Bean
    public MessageChannel mqttOutboundChannel() {
        return new DirectChannel();
    }

    /**
     * 配置MQTT Outbound适配器。
     * 这个适配器用于将消息从应用发送到MQTT代理的指定主题。
     * setAsync设置为true，意味着消息发送将异步进行。
     * setDefaultTopic设置了默认的目标主题。
     */
    @Bean
    @ServiceActivator(inputChannel = "mqttOutboundChannel")
    public MessageHandler mqttOutbound() {
        MqttPahoMessageHandler messageHandler = new MqttPahoMessageHandler(clientId + "_outbound", mqttClientFactory());
        messageHandler.setAsync(true);
        messageHandler.setDefaultTopic("topic1");
        return messageHandler;
    }
}